﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace Etapa1.SofRender
{
    public enum Mode
    {
        WRAP,CLAMP
    }

    public enum InterpolationMode
    {
        POINT,BILINEAR
    }
    
    public class TextureSampler
    {
        Color[] texture;
        int Height;
        int Width;
        Mode mode;
        InterpolationMode interpolationMode = InterpolationMode.BILINEAR;

        private TextureSampler() { }

        public static TextureSampler Sampler(Texture2D tex,Mode mode)
        {
            TextureSampler ts = new TextureSampler();
            ts.texture = new Color[tex.Height * tex.Width];
            tex.GetData<Color>(ts.texture);
            ts.Width = tex.Width;
            ts.Height = tex.Height;
            ts.mode = mode;
            return ts;
        }

        public static TextureSampler Sampler(Texture2D tex, Mode mode, InterpolationMode InterpolationMode)
        {
            TextureSampler ts = new TextureSampler();
            ts.texture = new Color[tex.Height * tex.Width];
            tex.GetData<Color>(ts.texture);
            ts.Width = tex.Width;
            ts.Height = tex.Height;
            ts.mode = mode;
            ts.interpolationMode = InterpolationMode;
            return ts;
        }

        public static TextureSampler Sampler(Texture2D tex)
        {
            return Sampler(tex, Mode.CLAMP);
        }

        public Color Text2D(Vector4 textCoord)
        {            

            if (interpolationMode == InterpolationMode.POINT)
            {

                float x = textCoord.X;
                float y = textCoord.Y;
                int xx = (int)(x * (Width - 1));
                int yy = (int)(y * (Height - 1));
                return getTexel(xx, yy);
            }
            else if (interpolationMode == InterpolationMode.BILINEAR)
            {
                double xx = (textCoord.X * (Width - 1));
                double yy = (textCoord.Y * (Height - 1));

                int x = (int)Math.Floor(xx);
                int y = (int)Math.Floor(yy);

                double ffx = xx - x;
                double ffy = yy - y;
                float fx = (float)ffx;
                float fy = (float)ffy;

                ///WIKI >> ALL
                //1. Uf * Vf
                //2. (1 - Uf) * Vf
                //3. (1 - Uf) * (1 - Vf)
                //4. Uf * (1 - Vf)

                float i4 = fx * fy;
                float i3 = (1 - fx) * fy;
                float i2 = fx * (1 - fy);
                float i1 = (1 - fx) * (1 - fy);                

                return new Color(getTexelVec4(x, y) * i1 + getTexelVec4(x +1, y) * i2 + getTexelVec4(x, y+1) * i3 + getTexelVec4(x+1, y+1) * i4);
            }
            else
            {
                throw new Exception("nao definido ...");
            }
        }

        Color getTexel(int x, int y)
        {
            return getTexel(new Vector2(x,y));
        }

        Color getTexel(Vector2 textCoord)
        {
            if (mode == Mode.CLAMP)
            {
                if (textCoord.X > (Width - 1))
                    textCoord.X = Width - 1;
                if (textCoord.Y > (Height - 1))
                    textCoord.Y = Height - 1;
                if (textCoord.X < 0)
                    textCoord.X = 0;
                if (textCoord.Y < 0)
                    textCoord.Y = 0;
            }
            else if (mode == Mode.WRAP)
            {
                textCoord.X = textCoord.X % (Width -1);
                textCoord.Y = textCoord.Y % (Height - 1);
            }

            return texture[(int)textCoord.Y * Width + (int)textCoord.X];
        }

        Vector4 getTexelVec4(int xx, int yy)
        {
            return getTexel(new Vector2(xx, yy)).ToVector4();            
        }
    }
}
